/*=============================================================================
#
# Author: liuxu - liuxu-0703@163.com
#
# Last modified: 2016-01-11 10:19
#
=============================================================================*/

#include <jni.h>
#include <string.h>
#include <android/log.h>
#include "com_senmo_video_jni_JNI.h"
#include "cnplayer.h"

#define LOG_TAG "SenMoJNI"
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__) 
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG , LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO  , LOG_TAG, __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN  , LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR  , LOG_TAG, __VA_ARGS__)


CCnPlayer* player;


JNIEXPORT jboolean JNICALL Java_com_senmo_video_jni_JNI_init(JNIEnv *env, jclass cls,
    jstring phone, jstring version)
{
    char* c_phone = (char *) (env)->GetStringUTFChars(phone, JNI_FALSE);
    char* c_version = (char *) (env)->GetStringUTFChars(version, JNI_FALSE);
    LOGI("jni init called, phone=%s, version=%s", c_phone, c_version);
    
    player = CCnPlayer::Instance();
    bool success = player->Init(c_phone, c_version);
    
    return JNI_FALSE;
}


JNIEXPORT void JNICALL Java_com_senmo_video_jni_JNI_dinit(JNIEnv *env, jclass cls)
{
    LOGI("jni dinit called");
    player->Dinit();
}


JNIEXPORT jint JNICALL Java_com_senmo_video_jni_JNI_connect(JNIEnv *env, jclass cls, jstring url)
{
    char* c_url = (char *) (env)->GetStringUTFChars(url, JNI_FALSE);
    LOGI("jni connect called, url=%s", c_url);
    int handle = player->Connect(c_url);
    return handle;
}


JNIEXPORT void JNICALL Java_com_senmo_video_jni_JNI_disconnect(JNIEnv *env, jclass cls, jint handle)
{
    LOGI("jni disconnect called, handle=%d", handle);
    player->Disconnect(handle);
}


JNIEXPORT jint JNICALL Java_com_senmo_video_jni_JNI_getConnectResult(JNIEnv *env, jclass cls, jint handle)
{
    LOGI("jni getConnectResult called, handle=%d", handle);
    int ret = player->GetConnectResult(handle);
    return ret;
}


JNIEXPORT void JNICALL Java_com_senmo_video_jni_JNI_yuv2rgb(JNIEnv *env, jclass cls,
    jbyteArray yuv_data, jint yLen, jint uLen, jint vLen,
    jintArray rgb_data, jint width, jint height, jint yStride, jint uvStride)
{
    char* yuv = (char*) env->GetByteArrayElements(yuv_data, NULL);
    int* rgb = (int*) env->GetIntArrayElements(rgb_data, NULL);
    
    CCnPlayer::ConvertYUVtoRGB(yuv, yLen, uLen, vLen, rgb, width, height, yStride, uvStride);
    
    env->ReleaseByteArrayElements(yuv_data, (jbyte*) yuv, 0);
    env->ReleaseIntArrayElements(rgb_data, (jint*) rgb, 0);
}


JNIEXPORT jobject JNICALL Java_com_senmo_video_jni_JNI_getMediaData
    (JNIEnv *env, jclass cls, jobject frame_data)
{
    //LOGI("jni getMediaData called");
    jclass clazz = env->FindClass("com/senmo/video/jni/FrameData");

    jfieldID f_buffer = env->GetFieldID(clazz, "data", "[B");
    jfieldID f_valid = env->GetFieldID(clazz, "valid", "Z");
    jfieldID f_handle = env->GetFieldID(clazz, "handle", "I");
    jfieldID f_len = env->GetFieldID(clazz, "len", "I");
    jfieldID f_yLen = env->GetFieldID(clazz, "yLen", "I");
    jfieldID f_uLen = env->GetFieldID(clazz, "uLen", "I");
    jfieldID f_vLen = env->GetFieldID(clazz, "vLen", "I");
    jfieldID f_yStride = env->GetFieldID(clazz, "yStride", "I");
    jfieldID f_uvStride = env->GetFieldID(clazz, "uvStride", "I");
    jfieldID f_errorCode = env->GetFieldID(clazz, "errorCode", "I");
    jfieldID f_width = env->GetFieldID(clazz, "width", "J");
    jfieldID f_height = env->GetFieldID(clazz, "height", "J");
    jfieldID f_deviceFlowRate = env->GetFieldID(clazz, "deviceFlowRate", "F");
    jfieldID f_clientFlowRate = env->GetFieldID(clazz, "clientFlowRate", "F");

    int handle = env->GetIntField(frame_data, f_handle);
    jbyteArray buffer = (jbyteArray) env->GetObjectField(frame_data, f_buffer);
    char* pBuffer = (char*) env->GetByteArrayElements(buffer, NULL);
    //LOGI("jni getMediaData called, handle=%d", handle);

    int len, yLen, uLen, vLen;
    int yStride, uvStride;
    int errcode;
    long w, h;
    float deviceFlowRate, clientFlowRate;
    bool valid = player->GetMediaData(handle, pBuffer,
        len, yLen, uLen, vLen, w, h, yStride, uvStride,
        errcode, deviceFlowRate, clientFlowRate);

    env->SetIntField(frame_data, f_valid, valid);
    env->SetIntField(frame_data, f_len, len);
    env->SetIntField(frame_data, f_yLen, yLen);
    env->SetIntField(frame_data, f_uLen, uLen);
    env->SetIntField(frame_data, f_vLen, vLen);
    env->SetIntField(frame_data, f_yStride, yStride);
    env->SetIntField(frame_data, f_uvStride, uvStride);
    env->SetIntField(frame_data, f_errorCode, errcode);
    env->SetLongField(frame_data, f_width, w);
    env->SetLongField(frame_data, f_height, h);
    env->SetFloatField(frame_data, f_deviceFlowRate, deviceFlowRate);
    env->SetFloatField(frame_data, f_clientFlowRate, clientFlowRate);

    env->ReleaseByteArrayElements(buffer, (jbyte*) pBuffer, 0);
    return frame_data;
}


// ====================================================


// ====================================================


jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
    void *venv;
    LOGI("dufresne----->JNI_OnLoad!");
    if (vm->GetEnv((void**)&venv, JNI_VERSION_1_4) != JNI_OK) {
        LOGE("dufresne--->ERROR: GetEnv failed");
        return -1;
    }
    return JNI_VERSION_1_4;
}

